package org.jeese.common.config;

import java.util.HashMap;
import java.util.Map;

import javax.servlet.Filter;

import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.session.SessionListener;
import org.apache.shiro.session.mgt.ExecutorServiceSessionValidationScheduler;
import org.apache.shiro.session.mgt.SessionManager;
import org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO;
import org.apache.shiro.session.mgt.eis.JavaUuidSessionIdGenerator;
import org.apache.shiro.session.mgt.eis.SessionDAO;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.CookieRememberMeManager;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.jeese.common.listener.ShiroSessionListener;
import org.jeese.common.shiro.ShiroAuthorizingRealm;
import org.jeese.common.shiro.ShiroLoginFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.filter.DelegatingFilterProxy;

import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
@Configuration
public class ShiroConfig {
	private static final Logger logger = LoggerFactory.getLogger(ShiroConfig.class);
	/**
	 * 必须添加否则shiro标签无法使用
	 * @return
	 */
	@Bean  
	public ShiroDialect shiroDialect(){  
		return new ShiroDialect();
	}
	
	/**
	 * 会话验证调度器,以让无效的session释放
	 * @return
	 */
	@Bean(name = "sessionValidationScheduler")
	public ExecutorServiceSessionValidationScheduler sessionValidationScheduler() {
		ExecutorServiceSessionValidationScheduler scheduler = new ExecutorServiceSessionValidationScheduler();
		//设置调度时间间隔，单位毫秒，默认就是1小时
		scheduler.setInterval(3600000);
		return scheduler;
	}
	
	/**
	 * 会话sessionDao
	 * @return
	 */
	@Bean("sessionDao")
    public SessionDAO sessionDao(){
    	EnterpriseCacheSessionDAO sessionDao = new EnterpriseCacheSessionDAO();
    	sessionDao.setActiveSessionsCacheName("shiro-session-cache");
    	sessionDao.setSessionIdGenerator(new JavaUuidSessionIdGenerator());
    	sessionDao.setCacheManager(cacheManager());
		return sessionDao;
    	
    }

    /**
     * 会话session管理器
     * @return
     */
    @Bean("sessionManager")
	public SessionManager sessionManager() {
        DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
        sessionManager.setGlobalSessionTimeout(3600000);
        sessionManager.setSessionValidationScheduler(sessionValidationScheduler());
        sessionManager.setSessionValidationSchedulerEnabled(true);
        sessionManager.setDeleteInvalidSessions(true);
        sessionManager.setSessionIdUrlRewritingEnabled(false);
        sessionManager.setSessionIdCookieEnabled(true);
        sessionManager.setSessionIdCookie(sessionIdCookie());
        sessionManager.setSessionDAO(sessionDao());
        //session监听器
        //sessionManager.getSessionListeners().add(sessionListener());
        return sessionManager;
    }
    
	/**
	 * 权限管理器
	 * @return
	 */
	@Bean("securityManager")
	public SecurityManager securityManager() {
		DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
		securityManager.setRealm(shiroAuthorizingRealm());
		securityManager.setSessionManager(sessionManager());
		securityManager.setCacheManager(cacheManager());
		// 设置rememberMe管理器
		securityManager.setRememberMeManager(rememberMeManager());
		return securityManager;
	}
	
	/**
	 * 授权Realm
	 * @return
	 */
	@Bean("shiroAuthorizingRealm")
	public ShiroAuthorizingRealm shiroAuthorizingRealm() {
		ShiroAuthorizingRealm shiroAuthorizingRealm = new ShiroAuthorizingRealm();
		// 设置缓存管理器
		shiroAuthorizingRealm.setCacheManager(cacheManager());
		return new ShiroAuthorizingRealm();
	}
    
    /**
     * 缓存管理器
     * @return
     */
    @Bean(value="cacheManage")
    public EhCacheManager cacheManager() {
        EhCacheManager cacheManager = new EhCacheManager();                
        cacheManager.setCacheManagerConfigFile("classpath:cache/spring-ehcache.xml");
        return cacheManager;
    }
    
    /**
     * 记住我cookie;
     * @return
     */
    @Bean("rememberMeCookie")
    public SimpleCookie rememberMeCookie() {
        // 这个参数是cookie的名称，对应前端的checkbox 的name = rememberMe
        SimpleCookie cookie = new SimpleCookie("rememberMe");
        cookie.setHttpOnly(true);
        //7天,采用spring el计算方便修改[细节决定成败]！
        cookie.setMaxAge(7 * 24 * 60 * 60);
        return cookie;
    }
    
    /**
     * 会话cookie
     * @return
     */
    @Bean("sessionIdCookie")
    public SimpleCookie sessionIdCookie() {
        SimpleCookie cookie = new SimpleCookie("JEESE-JSESSION-ID");
        //secure值为true时，在http中是无效的；在https中才有效。
        //cookie.setSecure(false);
        cookie.setHttpOnly(true);
        cookie.setPath("/");
        cookie.setMaxAge(-1);
        return cookie;
    }
    

    /**
     * 记住我管理器;
     * @return
     */
    @Bean(name = "rememberMeManager")
    public CookieRememberMeManager rememberMeManager() {
        CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
        cookieRememberMeManager.setCookie(rememberMeCookie());
        return cookieRememberMeManager;
    }
    
    
    /**
     * 保证实现了Shiro内部lifecycle函数的bean执行
     * @return
     */
    @Bean("lifecycleBeanPostProcessor")
    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }

    /**
     * AOP式方法级权限检查
     * @return
     */
    @Bean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator proxyCreator = new DefaultAdvisorAutoProxyCreator();
        proxyCreator.setProxyTargetClass(true);
        return proxyCreator;
    }
    
    /**
     * 开启aop使用注解@RequiresPermissions
     * @param securityManager
     * @return
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor() {
        AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
        advisor.setSecurityManager(securityManager());
        return advisor;
    }
    
    /**
     * 登录过滤器
     * @return
     */
    @Bean
	public ShiroLoginFilter shiroLoginFilter() {
		return new ShiroLoginFilter();
	}
    
    /**
     * session监听器
     * @return
     */
    @Bean("sessionListener")
    public SessionListener sessionListener() {
        return new ShiroSessionListener();
    }
    
    /**
     * shiro过滤器
     * @return
     */
    @Bean("shiroFilter")
    public ShiroFilterFactoryBean shirFilter() {
    	logger.info("init shiroFilter");
    	
        ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();
        shiroFilter.setSecurityManager(securityManager());
        //添加过滤器
        Map<String, Filter> filters=new HashMap<String, Filter>();
        filters.put("author",shiroLoginFilter());
        shiroFilter.setFilters(filters);
        // 未登录跳转地址
        shiroFilter.setLoginUrl("/login.html");
        // 登录成功后跳转地址
        shiroFilter.setSuccessUrl("/index.html");
        //未授权界面;
        shiroFilter.setUnauthorizedUrl("/403.html");
        return shiroFilter;
    }
    
    /**
     * 注册shiro过滤器
     * @return
     */
    @Bean
    public FilterRegistrationBean shiroFilterRegistration() {
    	logger.info("init shiroFilterRegistration");
        FilterRegistrationBean registration = new FilterRegistrationBean();
        registration.setFilter(new DelegatingFilterProxy("shiroFilter"));
        //该值缺省为false，表示生命周期由SpringApplicationContext管理，设置为true则表示由ServletContainer管理
        registration.addInitParameter("targetFilterLifecycle", "true");
        registration.setEnabled(true);
        registration.setOrder(Integer.MAX_VALUE - 1);
        registration.addUrlPatterns("/*");
        return registration;
    }
    
}
